/* Copyright (C) 2010 Luca Piccinelli
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "imgops/filters/SobelFilterOp.h"
#include "common/utility_data_structures.h"

#include <map>
#include <string>
#include <highgui.h>

namespace NAMESPACE{

// ****** Functor implementation ***********************************************
bool SobelFilterFunc::operator()(const cv::Mat& src, cv::Mat& dst,
                                 int ddepth,
                                 int xorder, int yorder,
                                 int ksize,
                                 double scale, double delta,
                                 int borderType){

    cv::Sobel(src, dst, ddepth, xorder, yorder, ksize, scale, delta, borderType);
    return true;
}
// -----------------------------------------------------------------------------

// ****** Constants assignment *************************************************
const size_t SobelFilterOp::MIN_INPUT_NUM = 1;
const size_t SobelFilterOp::MIN_CRITERIA_NUM = 3;
const size_t SobelFilterOp::MIN_OUTPUT_NUM = 1;
// -----------------------------------------------------------------------------

// ****** Operation implementation *********************************************
SobelFilterOp::~SobelFilterOp(){}
SobelFilterOp::SobelFilterOp() : AbstractOperation<SobelFilterFunc>(){

    min_input_num = MIN_INPUT_NUM;
    min_criteria_num = MIN_CRITERIA_NUM;
    min_output_num = MIN_OUTPUT_NUM;

    k1.set_key(INPUT_NS,  "img"); k1.setType(TypeParseTraits<cv::Mat*>::name());
    k2.set_key(OUTPUT_NS, "img"); k2.setType(TypeParseTraits<cv::Mat*>::name());

    k3.set_key(CRITERIA_NS, "depth"); k3.setType(TypeParseTraits<int>::name());
    k4.set_key(CRITERIA_NS, "order.derivative.x"); k4.setType(TypeParseTraits<int>::name());
    k5.set_key(CRITERIA_NS, "order.derivative.y"); k5.setType(TypeParseTraits<int>::name());
    k6.set_key(CRITERIA_NS, "size"); k6.setType(TypeParseTraits<double>::name());
    k7.set_key(CRITERIA_NS, "scale"); k7.setType(TypeParseTraits<double>::name());
    k8.set_key(CRITERIA_NS, "delta"); k8.setType(TypeParseTraits<double>::name());
    k9.set_key(CRITERIA_NS, "constant"); k9.setType(TypeParseTraits<int>::name());

    input_keys->push_back(k1);
    output_keys->push_back(k2);

    criteria_keys->push_back(k3);
    criteria_keys->push_back(k4);
    criteria_keys->push_back(k5);
    criteria_keys->push_back(k6);
    criteria_keys->push_back(k7);
    criteria_keys->push_back(k8);
    criteria_keys->push_back(k9);
}
SobelFilterOp::SobelFilterOp(const SobelFilterOp& gbo) : AbstractOperation<SobelFilterFunc>(gbo){}
SobelFilterOp& SobelFilterOp::operator=(const SobelFilterOp& gbo){
    if(this == &gbo) return *this;
    AbstractOperation<SobelFilterFunc>::operator=(gbo);
    return *this;
}

bool SobelFilterOp::doOperation(const std::list<input_t>& inputs,
                              const std::list<criteria_t>& operationCriteria,
                              std::list<output_t>& outputs) throw(bad_io_mapping){

    AbstractOperation<SobelFilterFunc>::prepareIO(inputs, operationCriteria, outputs);

    cv::Mat* in_img  = boost::any_cast<cv::Mat*>( ((*input_mapping) [k1])->getElement() );
    cv::Mat* out_img = boost::any_cast<cv::Mat*>( ((*output_mapping)[k2])->getElement() );

    int ddepth  = boost::any_cast<int>( ((*criteria_mapping)[k3])->getElement() );
    int xorder = boost::any_cast<int>( ((*criteria_mapping)[k4])->getElement() );
    int yorder = boost::any_cast<int>( ((*criteria_mapping)[k5])->getElement() );

    // Optional parameters
    IOElement* io_ksize = (*criteria_mapping)[k6];
    IOElement* io_scale = (*criteria_mapping)[k7];
    IOElement* io_delta = (*criteria_mapping)[k8];
    IOElement* io_border_type = (*criteria_mapping)[k9];

    int ksize = io_ksize ? boost::any_cast<int>( io_ksize->getElement() ) : 3;
    double scale = io_scale ? boost::any_cast<double>( io_scale->getElement() ) : 1;
    double delta = io_delta ? boost::any_cast<double>( io_delta->getElement() ) : 0;
    int border_type = io_border_type ? boost::any_cast<int>( io_border_type->getElement() ) : cv::BORDER_DEFAULT;

    (*operation)(*in_img, *out_img,
                 ddepth,
                 xorder, yorder,
                 ksize,
                 scale, delta,
                 border_type);        

    return true;
}

bool SobelFilterOp::operator==(const AbstractOperation<operation_t>& op) const{
    return AbstractOperation<SobelFilterFunc>::operator==(op);
}

bool SobelFilterOp::operator!=(const AbstractOperation<operation_t>& op) const{
    return !operator==(op);
}
// -----------------------------------------------------------------------------

}
